/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
package com.godenwater.recv.server.szy206;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;

import org.apache.commons.lang.StringUtils;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.gov.mwr.szy206.IMessage;
import cn.gov.mwr.szy206.IMessageHeader;
import cn.gov.mwr.szy206.SzyBuilder;
import cn.gov.mwr.szy206.utils.ByteUtil;

/**
 * An UDP client taht just send thousands of small messages to a UdpServer.
 * 
 * This class is used for performance test purposes. It does nothing at all, but
 * send a message repetitly to a server.
 * 
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
 */
public class SzyClient extends IoHandlerAdapter implements Runnable {

	private Logger logger = LoggerFactory.getLogger(SzyClient.class);

	/** The connector */
	private IoConnector connector;

	/** The session */
	private static IoSession session;

	private boolean received = false;

	/**
	 * Create the UdpClient's instance
	 */
	public SzyClient() {
		connector = new NioSocketConnector();
		connector.getFilterChain().addLast("codec",
				new ProtocolCodecFilter(new SzyCodecFactory(false)));
		connector.setHandler(this);

		SocketSessionConfig dcfg = (SocketSessionConfig) connector
				.getSessionConfig();
		dcfg.setWriteTimeout(30);
		// 创建连接
		ConnectFuture connFuture = connector.connect(new InetSocketAddress(
				"localhost", 5017));// 20011
		// ConnectFuture connFuture = connector.connect(new InetSocketAddress(
		// "223.4.209.1", 8088));
		// 等待连接创建完成
		connFuture.awaitUninterruptibly();

		// 获取session
		session = connFuture.getSession();

		// cmd.setCenterAddr(ByteUtil.HexStringToBinary("FF"));
		// cmd.setStationAddr(ByteUtil.HexStringToBinary("0012345678"));
		// cmd.setPassword(ByteUtil.HexStringToBinary("FFFF"));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		// cause.printStackTrace();
		logger.info(">> Client 会话出现异常  " + session.getRemoteAddress() + " \t"
				+ cause.getMessage(), cause);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		received = true;

		// 纯粹只处理报文，此消息体已经被解码为单体报文
		IMessage msg = (IMessage) message;
		IMessageHeader header = msg.getHeader();

		System.out.println(">> ST " + SzyBuilder.toHexString(msg));

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void sessionClosed(IoSession session) throws Exception {
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void sessionCreated(IoSession session) throws Exception {
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void sessionOpened(IoSession session) throws Exception {
	}

	@Override
	public void run() {
		int i = 0;
		try {
			while (i <= 10) {
				sendCommand("C0");
				i++;
				Thread.sleep(30000);
			}

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void stop() {
		if (connector.isActive()) {
			connector.dispose(true);
		}
	}

	protected void sendCommand(String command) {

		// ------------------------------
		if (StringUtils.isNotEmpty(command)) {

			command = StringUtils.trim(command).toUpperCase();

			System.out.println(this + "-----遥测站发送报文-----功能码：0x" + command
					+ "-----");

			if (command.length() == 2) {

				byte[] funcCode = ByteUtil.HexStringToBinary(command);
				switch (funcCode[0]) {
				case (byte) 0xc0:// 数据报文
					sendC0Message();
					break;
				case 0x02: // 链路检测
					
					break;
				case 0x10:// 设置遥测终端、中继站地址

					break;
				case 0x11:// 设置遥测终端、中继站时钟

					break;
				case 0x12:// 设置遥测终端工作模式

					break;
				case 0x15:// 设置遥测终端本次充值量

					break;
				case 0x16:// 设置遥测终端剩余水量报警值

					break;
				case 0x17:// 设置遥测终端水位基值、水位上下限

					break;
				case 0x18:// 设置遥测终端水压上、下限
				case 0x19:// 设置遥测终端水质参数种类、上限值
				case 0x1A:// 设置遥测终端水质参数种类、下限值
				case 0x1B:// 设置遥测终端站水量的表底（初始）值
				case 0x1C:// 设置遥测终端转发中继引导码长
				case 0x1D:// 设置中继站转发终端地址
				case 0x1E:// 设置中继站工作机自动切换，自报状态
				case 0x1F:// 设置遥测终端流量参数上限值
				case 0x20:// 设置遥测终端检测参数启报阈值及固态存储时间段间隔

				case 0x30:// 设置遥测终端IC卡功能有效
				case 0x31:// 取消遥测终端IC卡功能
				case 0x32:// 定值控制投入
				case 0x33:// 定值控制退出
				case 0x34:// 定值量设定
					// sendMessage(command);
				}
			}else{
				sendMessage(command.trim());
			}

		}
	}

	public void sendC0Message() {
		String hexstr = "681368B13201010001C00000000100530037401122004F16";
		byte[] message = ByteUtil.HexStringToBinary(hexstr);
		session.write(message);

	}

	public void send32Message() {
		String hexstr = "7E7EFF0000000003FFFF32005E020024130503160000F1F1000000000348F0F01305031500F460000000000000000000000000F5C0000B000B000B000B000B000BFFFF000B000B000B000B000BF0F0130503160020190000001F190000002619000030391A0000123812126003B98B";
		byte[] message = ByteUtil.HexStringToBinary(hexstr);
		session.write(message);

	}

	public void send33Message() {
		String hexstr = "01464630303132333435363738303030413333303034310230303034313330333037303631383330535420303031323334353637382048205454203133303330373036313820505220303030322E302056542031322E3333200335383337";
		byte[] message = ByteUtil.HexStringToBinary(hexstr);
		session.write(message);

	}

	public void sendMessage(String szy) {
		String hexString = szy;
		byte[] message = ByteUtil.HexStringToBinary(hexString);
		session.write(message);
	}

	/**
	 * The main method : instanciates a client, and send N messages. We sleep
	 * between each K messages sent, to avoid the server saturation.
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {

		// 将数据长度与前四位整合

		// for (int i = 1; i <= 500; i++) {
		SzyClient client = new SzyClient();
		// Thread thread = new Thread(client);
		// thread.start();
		// }

		InputStreamReader is = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(is);
		try {
			String cmd = "";

			boolean flag = true;
			System.out.print("Szy Client>>");
			while (flag) {
				cmd = br.readLine();
				if (cmd.equalsIgnoreCase("exit")
						|| cmd.equalsIgnoreCase("quit")) {
					client.stop();
					flag = false;
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.exit(0);

				} else if (cmd.equalsIgnoreCase("help")) {
					SzyHelp.printHelp();
				} else {
					client.sendCommand(cmd);
				}

				System.out.print("Hydro Client>>");
			}

		} catch (IOException e) {
			System.out.println("系统错误！");
			e.printStackTrace();
		} finally {
			try {
				is.close();
				br.close();
			} catch (IOException e) {
				System.out.println("关闭流发生错误！");
				e.printStackTrace();
			}
		}
	}
}
